home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-04-03 | 6.7 KB | 247 lines | [TEXT/KAHL] |
- /*
- *
- *
- * Faces.c, by Dave Johnson, 3/91.
- *
- * Based on Clifford Pickover's Chernoff face routine, in his book "Computers, Pattern, Chaos,
- * and Beauty."
- *
- *
- * The face is specified by an array of ten byte values ranging from -127 to 127. Here's how
- * the parameters map to facial features (there's no rhyme or reason here, I just used the
- * same set that Pickover did):
- *
- * 0 head eccentricity
- * 1 eye eccentricity
- * 2 pupil size
- * 3 eyebrow slope
- * 4 nose size
- * 5 mouth vert. offset
- * 6 eye spacing
- * 7 eye size
- * 8 mouth width
- * 9 mouth "openness"
- *
- *
- *
- */
-
- /* prototypes for the Face routines */
- void CenterRectOverPoint(Rect*, Point);
- Point GetCenter(Rect *theRect);
- int ScaleChar(char param, int max);
- pascal void Face(Rect *rect, char params[]);
-
- /*-------------------------------------------------------------------------
- CenterRectOverPoint() Centers theRect over thePt...
- --------------------------------------------------------------------------*/
- void CenterRectOverPoint(Rect *theRect, Point thePt)
- {
- /* First home theRect... */
- OffsetRect(theRect, -theRect->left, -theRect->top);
-
- /* ...then center it over thePt */
- OffsetRect(theRect, thePt.h - (theRect->right / 2), thePt.v - (theRect->bottom / 2));
- }
-
- /*-------------------------------------------------------------------------
- GetCenter() Returns the center of theRect
- --------------------------------------------------------------------------*/
- Point GetCenter(Rect *theRect)
- {
- Point pt;
-
- pt.h = theRect->left + ((theRect->right - theRect->left) / 2);
- pt.v = theRect->top + ((theRect->bottom - theRect->top) / 2);
- return(pt);
- }
-
- /*-------------------------------------------------------------------------
- ScaleChar() Scales param to a range of + or - max, returns the scaled value.
- param is assumed to be between -127 and 127.
- --------------------------------------------------------------------------*/
- int ScaleChar(char param, int max)
- {
- return ((long)param * max) / 127;
- }
-
- /*-------------------------------------------------------------------------
- Face() Draws a Chernoff face, scaled to bounds, in the current port
- --------------------------------------------------------------------------*/
- pascal void
- Face(Rect *bounds, char params[])
- {
- Rect rect, temprect;
- int x1, x2, y1, y2, xunit, yunit, temp;
- Point ctr, eyectr;
- PenState oldpen;
-
- /*
- * Set up
- */
-
- /* These are our basic units in x and y directions */
- xunit = (bounds->right - bounds->left) / 8;
- yunit = (bounds->bottom - bounds->top) / 8;
-
- /* The center of the face */
- ctr = GetCenter(bounds);
-
- /* Adjust the pen size */
- GetPenState(&oldpen);
- PenNormal();
- x1 = xunit / 10;
- if(x1 < 1)
- x1 = 1;
- y1 = yunit / 10;
- if(y1 < 1)
- y1 = 1;
- PenSize(x1, y1);
- EraseRect(bounds);
-
- /*
- * Draw the Head
- */
-
- /* Inset by one unit so there is room to squish around */
- rect = *bounds;
- InsetRect(&rect, xunit, yunit);
-
- /* Now add eccentricity (params[0], positive is taller) , and draw it */
- InsetRect(&rect, ScaleChar(params[0], xunit / 2), ScaleChar(-params[0], yunit / 2));
- FrameOval(&rect);
-
- /*
- * Draw the Eyes
- */
-
- /* Set up the default eye rect */
- SetRect(&rect, 0, 0, (5 * xunit) / 4, (5 * yunit) / 4);
-
- /* Change the size (param[7], positive is bigger) */
- InsetRect(&rect, ScaleChar(-params[7], xunit / 4), ScaleChar(-params[7], yunit / 4));
-
- /* Add eccentricity (param[1], positive is taller) */
- InsetRect(&rect, ScaleChar(params[1], xunit / 4), ScaleChar(-params[1], yunit / 4));
-
- /* Set location (params[6] is eye spacing, positive is wider), and draw
- the eyes. Also draw the pupils, while we're here. */
-
- temp = ScaleChar(params[6], xunit / 2);
- CenterRectOverPoint(&rect, ctr);
- temprect = rect; /* save for other eye */
- OffsetRect(&rect, -(xunit + temp), -((2 * yunit) / 3));
- FrameOval(&rect);
-
- /* Draw the pupil, params[2] is diameter, bigger is bigger.
- We want a minimum of a 1 pixel dot: no empty eyes */
-
- /* Convert params[2] to a positive number from 0 to 127 */
- x1 = (params[2] + 127) / 2;
-
- /* Scale in x and y directions, min of 1 */
- y1 = ScaleChar(x1, yunit / 3);
- if(y1 < 1) y1 = 1;
- x1 = ScaleChar(x1, xunit / 3);
- if(x1 < 1) x1 = 1;
-
- /* Get the center of the eye rect */
- eyectr = GetCenter(&rect);
-
- /* Set up the rect and draw it */
- SetRect(&rect, 0, 0, 0, 0);
- InsetRect(&rect, -x1, -y1);
- CenterRectOverPoint(&rect, eyectr);
- PaintOval(&rect);
-
- /* Other eye... */
- rect = temprect;
- OffsetRect(&rect, xunit + temp, -((2 * yunit) / 3));
- FrameOval(&rect);
-
- /* Pupil... */
- eyectr = GetCenter(&rect);
- SetRect(&rect, 0, 0, 0, 0);
- InsetRect(&rect, -x1, -y1);
- CenterRectOverPoint(&rect, eyectr);
- PaintOval(&rect);
-
- /*
- * Eyebrows
- */
-
- /* params[3] is slope, positive slopes down to the outside */
- temp = ScaleChar(params[3], yunit / 2);
- y1 = y2 = ctr.v - (yunit + (2 * yunit) / 3);
- y1 += temp;
- y2 -= temp;
- MoveTo(ctr.h - (3 * xunit) / 2, y1);
- LineTo(ctr.h - xunit / 2, y2);
- MoveTo(ctr.h + (3 * xunit) / 2, y1);
- LineTo(ctr.h + xunit / 2, y2);
-
- /*
- * Nose
- */
-
- /* params[4] is length, positive is bigger */
- y1 = yunit + (yunit / 3) + ScaleChar(params[4], yunit / 3);
- MoveTo(ctr.h, ctr.v - (yunit / 3));
- Line(xunit / 2, y1);
- Line(-xunit, 0);
-
- /*
- * Mouth
- */
-
- /* params[8] is width, positive is wider */
- temp = ScaleChar(params[8], xunit / 2);
- y1 = ctr.v + (2 * yunit); /* the neutral position, vertically */
- x1 = xunit + temp; /* the horizontal offset from center */
-
- /* Get the points for the lips */
- temp = ScaleChar(params[5], yunit / 3); /* offset for first lip */
-
- /* For lip 2, scale it */
- y2 = ScaleChar(params[9], yunit / 3); /* offset for the second lip (relative to first lip) */
- y2 += temp;
-
- /* Draw the first lip */
- if(temp > 0) /* if positive, use the bottom (smile) */
- {
- SetRect(&rect, ctr.h - x1, y1 - temp, ctr.h + x1, y1 + temp);
- FrameArc(&rect, 90, 180);
- }
- else if(temp < 0) /* if negative, use the top (frown) */
- {
- SetRect(&rect, ctr.h - x1, y1 + temp, ctr.h + x1, y1 - temp);
- FrameArc(&rect, -90, 180);
- }
- else /* if neutral, just draw a line */
- {
- MoveTo(ctr.h - x1, y1);
- LineTo(ctr.h + x1 - (xunit / 10), y1); /* subtract the pen width on the right */
- }
-
- /* Now the second lip */
- temp = y2;
- if(temp > 0) /* if positive, use the bottom (smile) */
- {
- SetRect(&rect, ctr.h - x1, y1 - temp, ctr.h + x1, y1 + temp);
- FrameArc(&rect, 90, 180);
- }
- else if(temp < 0) /* if negative, use the top (frown) */
- {
- SetRect(&rect, ctr.h - x1, y1 + temp, ctr.h + x1, y1 - temp);
- FrameArc(&rect, -90, 180);
- }
- else /* if neutral, just draw a line */
- {
- MoveTo(ctr.h - x1, y1);
- LineTo(ctr.h + x1 - (xunit / 10), y1); /* subtract the pen width on the right */
- }
-
- /* All Done! restore the pen and return */
- SetPenState(&oldpen);
- }
-